package com.smallframework.mvc;

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * Description:
 * User: Administrator
 * DateTime: 2017/7/2 0002 17:03
 */
public class ClassUtil {
    //private List<Class<?>> classes = new ArrayList<>();

    public static List<Class<?>> getAllClass(String packageName, boolean recursive) throws Exception {

        List<Class<?>> classes = new ArrayList<>();
        //TODO getContextClassLoader
        Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/"));
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if (url != null) {
                String protocol = url.getProtocol();
                if (protocol.equals("file")) {
                    String packagePath = url.getPath();
                    classes.addAll(getClassesByPath(packageName, packagePath, recursive));
                }
            }
        }

        return classes;
    }

    public static List<Class<?>> getClassesByPath(String packageName, String packagePath, boolean recursive) throws Exception {
        List<Class<?>> classes = new ArrayList<>();
        File dir = new File(packagePath);
        File[] childFiles = dir.listFiles((file) -> (file.isDirectory() || file.getName().endsWith(".class")));
        for (File file : childFiles) {
            //类文件
            if (!file.isDirectory()) {
                //去掉后面的 .class
                String className = file.getName().substring(0, file.getName().length() - 6);
                // classes.add(loader.loadClass(packageName + "." + className));
                classes.add(Class.forName(packageName + "." + className));
            } else {//文件夹

                if (recursive) {
                    classes.addAll(getClassesByPath(packageName + "." + file.getName(), packagePath + File.separator + file.getName(), recursive));
                }
            }
        }
        return classes;
    }

    public static List<Class<?>> getClassesByAnnotation(String packageName, Class<? extends Annotation> annotationClass) throws Exception {
        List<Class<?>> classes = getAllClass(packageName, true);
        List<Class<?>> annotationClasses = new ArrayList<>();
        for (Class<?> clazz : classes) {
            if (clazz.isAnnotationPresent(annotationClass)) {
                annotationClasses.add(clazz);
            }
        }
        return annotationClasses;
    }

    //获取方法 参数名
    public static String[] getMethodParamNames(Method method) throws NotFoundException {
        ClassPool classPool = ClassPool.getDefault();
        Class<?> clazz = method.getDeclaringClass();
        classPool.insertClassPath(new ClassClassPath(clazz));

        //TODO 方法什么时候返回null， 什么时候抛出notfound异常？
        CtClass ctClass = classPool.get(clazz.getName());

        CtMethod ctMethod = ctClass.getDeclaredMethod(method.getName());
        MethodInfo methodInfo = ctMethod.getMethodInfo();

        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();

        LocalVariableAttribute attribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attribute == null) {
            System.out.println("params  is null");
        }

        String[] paramNames = new String[ctMethod.getParameterTypes().length];
        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;

        if (attribute != null) {
            for (int i = 0; i < paramNames.length; i++) {
                paramNames[i] = attribute.variableName(i + pos);
            }
        }

        return paramNames;
    }


    public static void main(String[] args) throws IOException {

        String packageName = "com.smallframework.mvc";
        Thread.currentThread().getContextClassLoader().getResources(packageName.replace(".", "/"));

        System.out.println(ClassUtil.class.getResource(""));
        System.out.println(ClassUtil.class.getResource("/"));
        ClassLoader loader = ClassUtil.class.getClassLoader();
        Enumeration<URL> enumeration = loader.getResources("");
    }
}
